MATH 318 Final Project: The Effect of World Cup on Stock Price and Trading Activity

library(tidyverse)
library(dplyr)
library(MASS)
library(lubridate)
library(stringr)
library(GGally)
library(knitr)
library(kableExtra)

Load Data

spydata = as_tibble(read.csv("1_min_SPY_2008-2021.csv"))
worldcupmatches = as_tibble(read.csv("WorldCupMatches.csv"))

Helper Functions

Get Only Spy Data for a specific Game

#Clean SpyData Per Game
getSpyDataWithinRangeofGame = function(spydata,game_date,range){
  rangeInSeconds = 60 * 60 * range
  return(filter(spydata, (date >= game_date - rangeInSeconds) & (date <= game_date + rangeInSeconds)))
}

Check if there is Spy data for a game

hasSpyDataWithinRangeOfGame = function(spydata, game_dates, range){
  list = c()
  for(game_date in 1:length(game_dates)){
    list = append(list, nrow(getSpyDataWithinRangeofGame(spydata, game_date = game_dates[game_date], range)) != 0)
  }
  return(list)
}

Get Spy Data combined with Game Data for a set of Games

#Clean Spydata Per Worldcup Returns a set of spydata with their corresponding game data
getSpyAndGameDataWithinWorldcup = function(worldcup, spydata, range){
  z = getSpyDataWithinRangeofGame(spydata, worldcup[[1,"Datetime"]], range)
  gamerow = worldcup[1,]
  for(colIndx in 1: ncol(gamerow)){
      colvalue = worldcup[[1, colIndx]]
      colname = colnames(worldcup)[colIndx]
      z[colname] = rep(colvalue, times= nrow(z))
  }
  z["time.from.game"] = as.numeric(difftime(z$date, worldcup[[1,"Datetime"]],units = "secs"))
  for(gameIndx in 2:nrow(worldcup)){
   x = getSpyDataWithinRangeofGame(spydata, worldcup[[gameIndx,"Datetime"]], range)
   gamerow = worldcup[gameIndx,]
   for(colIndx in 1: ncol(gamerow)){
      colvalue = worldcup[[gameIndx, colIndx]]
      colname = colnames(worldcup)[colIndx]
      x[colname] = rep(colvalue, times= nrow(x))
   }
   x["time.from.game"] = as.numeric(difftime(x$date, x$Datetime, units = "secs"))
  
   z = union_all(z,x)
  }
  return(z)
}

Get Spy Data combined with Game Data for a single game

#Gives Spydata and Difference from the game time for each worldcup game
getSpyAndGameDataForOneGame = function(spydata,worldcup, game_index, range){
  z = getSpyDataWithinRangeofGame(spydata, worldcup[[game_index,"Datetime"]], range)
  for(colIndx in 1: ncol(worldcup[game_index,])){
      colvalue = worldcup[[game_index, colIndx]]
      colname = colnames(worldcup)[colIndx]
      z[colname] = rep(colvalue, times= nrow(z))
  }
  z["time.from.game"] = as.numeric(difftime(z$date, rep(worldcup[[game_index,"Datetime"]], times = nrow(z)), units="secs"))
  return(z)
}

Cleaning Data

#Update 
spydata$date = as.POSIXct(spydata$date, format="%Y%m%d %H:%M:%S")

#Remove Rows containing NA's
cleaned_worldcupmatches = unique(worldcupmatches[!apply(is.na(worldcupmatches) | worldcupmatches == "", 1, all),])

#Convert Date and Time into POSIX EDT 
cleaned_worldcupmatches$Datetime = as.POSIXct(cleaned_worldcupmatches$Datetime, format = "%e %b %Y - %R") - 60 * 60

#Filter Games on the Weekend
cleaned_worldcupmatches = filter(cleaned_worldcupmatches, wday(as.Date(Datetime)) != 7 & wday(as.Date(Datetime)) != 1)

#Filter Games that have no corresponding Data
cleaned_worldcupmatches = add_column(cleaned_worldcupmatches,"HasSpyData" = hasSpyDataWithinRangeOfGame(spydata, cleaned_worldcupmatches$Datetime, 3))
cleaned_worldcupmatches = filter(cleaned_worldcupmatches, cleaned_worldcupmatches$HasSpyData == TRUE)

cleaned_worldcupmatches

Get Spy Data

#Get Spy data within 3 hours of the Game For both World cups
allspydata2014 = getSpyAndGameDataWithinWorldcup(filter(cleaned_worldcupmatches, Year==2014), spydata, 3)

allspydata2010 = getSpyAndGameDataWithinWorldcup(filter(cleaned_worldcupmatches, Year==2010), spydata, 3)

Normalizing the average price

#Normalize the Data so that we can compare fairly the growth of stock price
max.2014 = max(allspydata2014$average)
max.2010 = max(allspydata2010$average)


min.2014 = min(allspydata2014$average)
min.2010 = min(allspydata2010$average)

difference.2014 = (max.2014) - (min.2014)
difference.2010 = (max.2010) - (min.2010)
normalized2014average = (allspydata2014$average-min.2014)/difference.2014
normalized2010average = (allspydata2010$average-min.2010)/difference.2010


allspydata2014 = add_column(allspydata2014, "normalized.average" = normalized2014average)
allspydata2010 = add_column(allspydata2010, "normalized.average" = normalized2010average)

allspydata = union_all(allspydata2014, allspydata2010)

allspydata
NA

Exploring the Relationship of Time and Volume

Let us explore the Correlation between the Time form game and the Price of the stock

Correlations

ggpairs(allspydata, columns = c("time.from.game", "average", "volume", "normalized.average"))

kable(cor(allspydata[, c(7,9,31,32)]))
volume average time.from.game normalized.average
volume 1.0000000 -0.4039908 0.0334462 0.1264736
average -0.4039908 1.0000000 0.2149680 -0.3961910
time.from.game 0.0334462 0.2149680 1.0000000 0.0158785
normalized.average 0.1264736 -0.3961910 0.0158785 1.0000000

Linear Regression

ggplot(allspydata) + geom_point(aes(time.from.game,normalized.average))

ggplot(allspydata, aes(time.from.game,log(volume))) + geom_point() + geom_smooth()

Sample Games from a World Cup

set.seed(100) 
samplesize = 10
worldcupmatches2014 = filter(cleaned_worldcupmatches, Year == 2014)
sampleworldcupgames = sample_n(worldcupmatches2014,size = samplesize)

print(worldcupmatches2014)
print(sampleworldcupgames)

After

game1 <- getSpyAndGameDataForOneGame(spydata, sampleworldcupgames, 1, 3)
volumesp1 <- ggplot(game1) + geom_point(mapping = aes(x=date, y=log(volume)), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[1]) + ggtitle("Volume over Time, Sample Game 1")
volumesp1

game2 <- getSpyAndGameDataForOneGame(spydata, sampleworldcupgames, 2, 3)
volumesp2 <- ggplot(game2) + geom_point(mapping = aes(x=date, y=log(volume)), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[2])+ ggtitle("Volume over Time, Sample Game 2")
volumesp2

#ERROR AGAIN WE DONT HAVE FULL DATA FOR THIS GAME
game3 <- getSpyAndGameDataForOneGame(spydata, sampleworldcupgames, 3, 3)
volumesp3 <- ggplot(game3) + geom_point(mapping = aes(x=date, y=log(volume)), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[3])+ ggtitle("Volume over Time, Sample Game 3")
volumesp3

game4 <- getSpyAndGameDataForOneGame(spydata, sampleworldcupgames, 4, 3)
volumesp4 <- ggplot(game4) + geom_point(mapping = aes(x=date, y=log(volume)), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[4])+ ggtitle("Volume over Time, Sample Game 4")
volumesp4

game5 <- getSpyAndGameDataForOneGame(spydata, sampleworldcupgames, 5, 3)
volumesp5 <- ggplot(game5) + geom_point(mapping = aes(x=date, y=log(volume)), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[5])+ ggtitle("Volume over Time, Sample Game 5")
volumesp5

Price Scatter Plots

Using average price

pricesp1 <- ggplot(game1) + geom_point(mapping = aes(x=date, y=average), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[1])+ ggtitle("Price over Time, Sample Game 1")
pricesp1

pricesp2 <- ggplot(game2) + geom_point(mapping = aes(x=date, y=average), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[2])+ ggtitle("Price over Time, Sample Game 2")
pricesp2

#ISSUE BECAUSE WE DONT HAVE DATA FOR 16:00 and that is time of the game
pricesp3 <- ggplot(game3) + geom_point(mapping = aes(x=date, y=average), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[3])+ ggtitle("Price over Time, Sample Game 3")
pricesp3

pricesp4 <- ggplot(game4) + geom_point(mapping = aes(x=date, y=average), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[4])+ ggtitle("Price over Time, Sample Game 4")
pricesp4

pricesp5 <- ggplot(game5, aes(date)) + geom_point(aes(y=average, ), color ="red") + geom_vline(xintercept= sampleworldcupgames$Datetime[5])+ ggtitle("Price over Time, Sample Game 5") + geom_col(aes(y=(volume))) + scale_y_continuous(sec.axis = sec_axis(~./100, name = "average"))
pricesp5

Just USA Games

worldcupmatchesUSAhome = filter(cleaned_worldcupmatches, Home.Team.Name == "USA")
worldcupmatchesUSAaway = filter(cleaned_worldcupmatches, Away.Team.Name == "USA")
worldcupmatchesUSA <- union_all(worldcupmatchesUSAaway,worldcupmatchesUSAhome)
worldcupmatchesUSA
game1USA <- getSpyAndGameDataForOneGame(spydata, worldcupmatchesUSA, 1, 3)
volumesp1USA <- ggplot(game1USA) + geom_point(mapping = aes(x=date, y=log(volume)), color ="red") + geom_vline(xintercept= worldcupmatchesUSA$Datetime[1])+ ggtitle("Volume over Time, USA Game 1, 2010")
volumesp1USA

game2USA <- getSpyAndGameDataForOneGame(spydata, worldcupmatchesUSA, 2, 3)
volumesp2USA <- ggplot(game2USA) + geom_point(mapping = aes(x=date, y=volume), color ="red") + geom_vline(xintercept= worldcupmatchesUSA$Datetime[2])+ ggtitle("Volume over Time, USA Game 2, 2014")
volumesp2USA

game3USA <- getSpyAndGameDataForOneGame(spydata, worldcupmatchesUSA, 3, 3)
volumesp3USA <- ggplot(game3USA) + geom_point(mapping = aes(x=date, y=volume), color ="red") + geom_vline(xintercept= worldcupmatchesUSA$Datetime[3])+ ggtitle("Volume over Time, USA Game 2, 2010")
volumesp3USA

game4USA <- getSpyAndGameDataForOneGame(spydata, worldcupmatchesUSA, 4, 3)
volumesp4USA <- ggplot(game4USA) + geom_point(mapping = aes(x=date, y=volume), color ="red") + geom_vline(xintercept= worldcupmatchesUSA$Datetime[4])+ ggtitle("Volume over Time, USA Game 1, 2014")
volumesp4USA

pricesp4USA <- ggplot(game4USA) + geom_point(mapping = aes(x=date, y=average), color ="red") + geom_vline(xintercept= worldcupmatchesUSA$Datetime[4])+ ggtitle("Price over Time, USA Game 1, 2014")
pricesp4USA

Is there a way to make money during World Cup Games?

What time should you look to sell?

price_list = c()
time_list = c()
for (game in 1:nrow(cleaned_worldcupmatches)) {
  price_game_data <- getSpyAndGameDataForOneGame(spydata, cleaned_worldcupmatches, game, 3)
  highestdatapoint = price_game_data[which.max(price_game_data$average),]
  highestpriceforgame <- highestdatapoint$average
  time <- highestdatapoint$"time.from.game"
  price_list = append(price_list, highestpriceforgame)
  time_list = append(time_list, time)
}
optimal_selling.df <- data.frame("price" = price_list, "time" = time_list)
optimal_selling.df

Do THis for Optimal Buying time?

#DO THIS FOR OPTIMAL TIME TO BUY?
ggplot(optimal_selling.df) + geom_histogram(mapping = aes(x= time)) + ggtitle("How Often Best Selling Time is vs. Time From Game")

What time should you look to buy?

price_list = c()
time_list = c()
for (game in 1:nrow(cleaned_worldcupmatches)) {
  price_game_data <- getSpyAndGameDataForOneGame(spydata, cleaned_worldcupmatches, game, 3)
  lowestdatapoint = price_game_data[which.min(price_game_data$average),]
  lowestpriceforgame <- lowestdatapoint$average
  time <- lowestdatapoint$"time.from.game"
  price_list = append(price_list, lowestpriceforgame)
  time_list = append(time_list, time)
}
ggplot(optimal_buying.df) + geom_histogram(mapping = aes(x= time)) + ggtitle("How Often Best Buying Time is vs. Time From Game")

Does the importance of the game matter in the total amount of trades?

#Translate Round ID

ggplot(allspydata, aes(volume, Stage)) + geom_boxplot()

LS0tCnRpdGxlOiAiTUFUSCAzMTggRmluYWwgUHJvamVjdCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKIyBNQVRIIDMxOCBGaW5hbCBQcm9qZWN0OiBUaGUgRWZmZWN0IG9mIFdvcmxkIEN1cCBvbiBTdG9jayBQcmljZSBhbmQgVHJhZGluZyBBY3Rpdml0eQoKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGRwbHlyKQpsaWJyYXJ5KE1BU1MpCmxpYnJhcnkobHVicmlkYXRlKQpsaWJyYXJ5KHN0cmluZ3IpCmxpYnJhcnkoR0dhbGx5KQpsaWJyYXJ5KGtuaXRyKQpsaWJyYXJ5KGthYmxlRXh0cmEpCmBgYAoKIyBMb2FkIERhdGEKCmBgYHtyfQpzcHlkYXRhID0gYXNfdGliYmxlKHJlYWQuY3N2KCIxX21pbl9TUFlfMjAwOC0yMDIxLmNzdiIpKQpgYGAKCmBgYHtyfQp3b3JsZGN1cG1hdGNoZXMgPSBhc190aWJibGUocmVhZC5jc3YoIldvcmxkQ3VwTWF0Y2hlcy5jc3YiKSkKYGBgCgojIEhlbHBlciBGdW5jdGlvbnMKCiMjIEdldCBPbmx5IFNweSBEYXRhIGZvciBhIHNwZWNpZmljIEdhbWUKCmBgYHtyfQojQ2xlYW4gU3B5RGF0YSBQZXIgR2FtZQpnZXRTcHlEYXRhV2l0aGluUmFuZ2VvZkdhbWUgPSBmdW5jdGlvbihzcHlkYXRhLGdhbWVfZGF0ZSxyYW5nZSl7CiAgcmFuZ2VJblNlY29uZHMgPSA2MCAqIDYwICogcmFuZ2UKICByZXR1cm4oZmlsdGVyKHNweWRhdGEsIChkYXRlID49IGdhbWVfZGF0ZSAtIHJhbmdlSW5TZWNvbmRzKSAmIChkYXRlIDw9IGdhbWVfZGF0ZSArIHJhbmdlSW5TZWNvbmRzKSkpCn0KYGBgCgojIyBDaGVjayBpZiB0aGVyZSBpcyBTcHkgZGF0YSBmb3IgYSBnYW1lCgpgYGB7cn0KaGFzU3B5RGF0YVdpdGhpblJhbmdlT2ZHYW1lID0gZnVuY3Rpb24oc3B5ZGF0YSwgZ2FtZV9kYXRlcywgcmFuZ2UpewogIGxpc3QgPSBjKCkKICBmb3IoZ2FtZV9kYXRlIGluIDE6bGVuZ3RoKGdhbWVfZGF0ZXMpKXsKICAgIGxpc3QgPSBhcHBlbmQobGlzdCwgbnJvdyhnZXRTcHlEYXRhV2l0aGluUmFuZ2VvZkdhbWUoc3B5ZGF0YSwgZ2FtZV9kYXRlID0gZ2FtZV9kYXRlc1tnYW1lX2RhdGVdLCByYW5nZSkpICE9IDApCiAgfQogIHJldHVybihsaXN0KQp9CmBgYAoKIyMgR2V0IFNweSBEYXRhIGNvbWJpbmVkIHdpdGggR2FtZSBEYXRhIGZvciBhIHNldCBvZiBHYW1lcwoKYGBge3J9CiNDbGVhbiBTcHlkYXRhIFBlciBXb3JsZGN1cCBSZXR1cm5zIGEgc2V0IG9mIHNweWRhdGEgd2l0aCB0aGVpciBjb3JyZXNwb25kaW5nIGdhbWUgZGF0YQpnZXRTcHlBbmRHYW1lRGF0YVdpdGhpbldvcmxkY3VwID0gZnVuY3Rpb24od29ybGRjdXAsIHNweWRhdGEsIHJhbmdlKXsKICB6ID0gZ2V0U3B5RGF0YVdpdGhpblJhbmdlb2ZHYW1lKHNweWRhdGEsIHdvcmxkY3VwW1sxLCJEYXRldGltZSJdXSwgcmFuZ2UpCiAgZ2FtZXJvdyA9IHdvcmxkY3VwWzEsXQogIGZvcihjb2xJbmR4IGluIDE6IG5jb2woZ2FtZXJvdykpewogICAgICBjb2x2YWx1ZSA9IHdvcmxkY3VwW1sxLCBjb2xJbmR4XV0KICAgICAgY29sbmFtZSA9IGNvbG5hbWVzKHdvcmxkY3VwKVtjb2xJbmR4XQogICAgICB6W2NvbG5hbWVdID0gcmVwKGNvbHZhbHVlLCB0aW1lcz0gbnJvdyh6KSkKICB9CiAgelsidGltZS5mcm9tLmdhbWUiXSA9IGFzLm51bWVyaWMoZGlmZnRpbWUoeiRkYXRlLCB3b3JsZGN1cFtbMSwiRGF0ZXRpbWUiXV0sdW5pdHMgPSAic2VjcyIpKQogIGZvcihnYW1lSW5keCBpbiAyOm5yb3cod29ybGRjdXApKXsKICAgeCA9IGdldFNweURhdGFXaXRoaW5SYW5nZW9mR2FtZShzcHlkYXRhLCB3b3JsZGN1cFtbZ2FtZUluZHgsIkRhdGV0aW1lIl1dLCByYW5nZSkKICAgZ2FtZXJvdyA9IHdvcmxkY3VwW2dhbWVJbmR4LF0KICAgZm9yKGNvbEluZHggaW4gMTogbmNvbChnYW1lcm93KSl7CiAgICAgIGNvbHZhbHVlID0gd29ybGRjdXBbW2dhbWVJbmR4LCBjb2xJbmR4XV0KICAgICAgY29sbmFtZSA9IGNvbG5hbWVzKHdvcmxkY3VwKVtjb2xJbmR4XQogICAgICB4W2NvbG5hbWVdID0gcmVwKGNvbHZhbHVlLCB0aW1lcz0gbnJvdyh4KSkKICAgfQogICB4WyJ0aW1lLmZyb20uZ2FtZSJdID0gYXMubnVtZXJpYyhkaWZmdGltZSh4JGRhdGUsIHgkRGF0ZXRpbWUsIHVuaXRzID0gInNlY3MiKSkKICAKICAgeiA9IHVuaW9uX2FsbCh6LHgpCiAgfQogIHJldHVybih6KQp9CmBgYAoKIyMgR2V0IFNweSBEYXRhIGNvbWJpbmVkIHdpdGggR2FtZSBEYXRhIGZvciBhIHNpbmdsZSBnYW1lCgpgYGB7cn0KI0dpdmVzIFNweWRhdGEgYW5kIERpZmZlcmVuY2UgZnJvbSB0aGUgZ2FtZSB0aW1lIGZvciBlYWNoIHdvcmxkY3VwIGdhbWUKZ2V0U3B5QW5kR2FtZURhdGFGb3JPbmVHYW1lID0gZnVuY3Rpb24oc3B5ZGF0YSx3b3JsZGN1cCwgZ2FtZV9pbmRleCwgcmFuZ2UpewogIHogPSBnZXRTcHlEYXRhV2l0aGluUmFuZ2VvZkdhbWUoc3B5ZGF0YSwgd29ybGRjdXBbW2dhbWVfaW5kZXgsIkRhdGV0aW1lIl1dLCByYW5nZSkKICBmb3IoY29sSW5keCBpbiAxOiBuY29sKHdvcmxkY3VwW2dhbWVfaW5kZXgsXSkpewogICAgICBjb2x2YWx1ZSA9IHdvcmxkY3VwW1tnYW1lX2luZGV4LCBjb2xJbmR4XV0KICAgICAgY29sbmFtZSA9IGNvbG5hbWVzKHdvcmxkY3VwKVtjb2xJbmR4XQogICAgICB6W2NvbG5hbWVdID0gcmVwKGNvbHZhbHVlLCB0aW1lcz0gbnJvdyh6KSkKICB9CiAgelsidGltZS5mcm9tLmdhbWUiXSA9IGFzLm51bWVyaWMoZGlmZnRpbWUoeiRkYXRlLCByZXAod29ybGRjdXBbW2dhbWVfaW5kZXgsIkRhdGV0aW1lIl1dLCB0aW1lcyA9IG5yb3coeikpLCB1bml0cz0ic2VjcyIpKQogIHJldHVybih6KQp9CmBgYAoKIyBDbGVhbmluZyBEYXRhCgpgYGB7cn0KI1VwZGF0ZSAKc3B5ZGF0YSRkYXRlID0gYXMuUE9TSVhjdChzcHlkYXRhJGRhdGUsIGZvcm1hdD0iJVklbSVkICVIOiVNOiVTIikKCiNSZW1vdmUgUm93cyBjb250YWluaW5nIE5BJ3MKY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMgPSB1bmlxdWUod29ybGRjdXBtYXRjaGVzWyFhcHBseShpcy5uYSh3b3JsZGN1cG1hdGNoZXMpIHwgd29ybGRjdXBtYXRjaGVzID09ICIiLCAxLCBhbGwpLF0pCgojQ29udmVydCBEYXRlIGFuZCBUaW1lIGludG8gUE9TSVggRURUIApjbGVhbmVkX3dvcmxkY3VwbWF0Y2hlcyREYXRldGltZSA9IGFzLlBPU0lYY3QoY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMkRGF0ZXRpbWUsIGZvcm1hdCA9ICIlZSAlYiAlWSAtICVSIikgLSA2MCAqIDYwCgojRmlsdGVyIEdhbWVzIG9uIHRoZSBXZWVrZW5kCmNsZWFuZWRfd29ybGRjdXBtYXRjaGVzID0gZmlsdGVyKGNsZWFuZWRfd29ybGRjdXBtYXRjaGVzLCB3ZGF5KGFzLkRhdGUoRGF0ZXRpbWUpKSAhPSA3ICYgd2RheShhcy5EYXRlKERhdGV0aW1lKSkgIT0gMSkKCiNGaWx0ZXIgR2FtZXMgdGhhdCBoYXZlIG5vIGNvcnJlc3BvbmRpbmcgRGF0YQpjbGVhbmVkX3dvcmxkY3VwbWF0Y2hlcyA9IGFkZF9jb2x1bW4oY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMsIkhhc1NweURhdGEiID0gaGFzU3B5RGF0YVdpdGhpblJhbmdlT2ZHYW1lKHNweWRhdGEsIGNsZWFuZWRfd29ybGRjdXBtYXRjaGVzJERhdGV0aW1lLCAzKSkKY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMgPSBmaWx0ZXIoY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMsIGNsZWFuZWRfd29ybGRjdXBtYXRjaGVzJEhhc1NweURhdGEgPT0gVFJVRSkKCmNsZWFuZWRfd29ybGRjdXBtYXRjaGVzCmBgYAoKIyMgR2V0IFNweSBEYXRhCgpgYGB7cn0KI0dldCBTcHkgZGF0YSB3aXRoaW4gMyBob3VycyBvZiB0aGUgR2FtZSBGb3IgYm90aCBXb3JsZCBjdXBzCmFsbHNweWRhdGEyMDE0ID0gZ2V0U3B5QW5kR2FtZURhdGFXaXRoaW5Xb3JsZGN1cChmaWx0ZXIoY2xlYW5lZF93b3JsZGN1cG1hdGNoZXMsIFllYXI9PTIwMTQpLCBzcHlkYXRhLCAzKQoKYWxsc3B5ZGF0YTIwMTAgPSBnZXRTcHlBbmRHYW1lRGF0YVdpdGhpbldvcmxkY3VwKGZpbHRlcihjbGVhbmVkX3dvcmxkY3VwbWF0Y2hlcywgWWVhcj09MjAxMCksIHNweWRhdGEsIDMpCgpgYGAKCiMjIE5vcm1hbGl6aW5nIHRoZSBhdmVyYWdlIHByaWNlCgpgYGB7cn0KI05vcm1hbGl6ZSB0aGUgRGF0YSBzbyB0aGF0IHdlIGNhbiBjb21wYXJlIGZhaXJseSB0aGUgZ3Jvd3RoIG9mIHN0b2NrIHByaWNlCm1heC4yMDE0ID0gbWF4KGFsbHNweWRhdGEyMDE0JGF2ZXJhZ2UpCm1heC4yMDEwID0gbWF4KGFsbHNweWRhdGEyMDEwJGF2ZXJhZ2UpCgoKbWluLjIwMTQgPSBtaW4oYWxsc3B5ZGF0YTIwMTQkYXZlcmFnZSkKbWluLjIwMTAgPSBtaW4oYWxsc3B5ZGF0YTIwMTAkYXZlcmFnZSkKCmRpZmZlcmVuY2UuMjAxNCA9IChtYXguMjAxNCkgLSAobWluLjIwMTQpCmRpZmZlcmVuY2UuMjAxMCA9IChtYXguMjAxMCkgLSAobWluLjIwMTApCm5vcm1hbGl6ZWQyMDE0YXZlcmFnZSA9IChhbGxzcHlkYXRhMjAxNCRhdmVyYWdlLW1pbi4yMDE0KS9kaWZmZXJlbmNlLjIwMTQKbm9ybWFsaXplZDIwMTBhdmVyYWdlID0gKGFsbHNweWRhdGEyMDEwJGF2ZXJhZ2UtbWluLjIwMTApL2RpZmZlcmVuY2UuMjAxMAoKCmFsbHNweWRhdGEyMDE0ID0gYWRkX2NvbHVtbihhbGxzcHlkYXRhMjAxNCwgIm5vcm1hbGl6ZWQuYXZlcmFnZSIgPSBub3JtYWxpemVkMjAxNGF2ZXJhZ2UpCmFsbHNweWRhdGEyMDEwID0gYWRkX2NvbHVtbihhbGxzcHlkYXRhMjAxMCwgIm5vcm1hbGl6ZWQuYXZlcmFnZSIgPSBub3JtYWxpemVkMjAxMGF2ZXJhZ2UpCgphbGxzcHlkYXRhID0gdW5pb25fYWxsKGFsbHNweWRhdGEyMDE0LCBhbGxzcHlkYXRhMjAxMCkKCmFsbHNweWRhdGEKCmBgYAoKIyMgCgojIEV4cGxvcmluZyB0aGUgUmVsYXRpb25zaGlwIG9mIFRpbWUgYW5kIFZvbHVtZQoKTGV0IHVzIGV4cGxvcmUgdGhlIENvcnJlbGF0aW9uIGJldHdlZW4gdGhlIFRpbWUgZm9ybSBnYW1lIGFuZCB0aGUgUHJpY2Ugb2YgdGhlIHN0b2NrCgojIyBDb3JyZWxhdGlvbnMKCmBgYHtyfQpnZ3BhaXJzKGFsbHNweWRhdGEsIGNvbHVtbnMgPSBjKCJ0aW1lLmZyb20uZ2FtZSIsICJhdmVyYWdlIiwgInZvbHVtZSIsICJub3JtYWxpemVkLmF2ZXJhZ2UiKSkKYGBgCgpgYGB7cn0Ka2FibGUoY29yKGFsbHNweWRhdGFbLCBjKDcsOSwzMSwzMildKSkKYGBgCgojIyBMaW5lYXIgUmVncmVzc2lvbgoKYGBge3J9CmdncGxvdChhbGxzcHlkYXRhKSArIGdlb21fcG9pbnQoYWVzKHRpbWUuZnJvbS5nYW1lLG5vcm1hbGl6ZWQuYXZlcmFnZSkpCmBgYAoKYGBge3J9CmdncGxvdChhbGxzcHlkYXRhLCBhZXModGltZS5mcm9tLmdhbWUsbG9nKHZvbHVtZSkpKSArIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkKCmBgYAoKIyBTYW1wbGUgR2FtZXMgZnJvbSBhIFdvcmxkIEN1cAoKYGBge3J9CnNldC5zZWVkKDEwMCkgCnNhbXBsZXNpemUgPSAxMAp3b3JsZGN1cG1hdGNoZXMyMDE0ID0gZmlsdGVyKGNsZWFuZWRfd29ybGRjdXBtYXRjaGVzLCBZZWFyID09IDIwMTQpCnNhbXBsZXdvcmxkY3VwZ2FtZXMgPSBzYW1wbGVfbih3b3JsZGN1cG1hdGNoZXMyMDE0LHNpemUgPSBzYW1wbGVzaXplKQpgYGAKCkFmdGVyCgpgYGB7cn0KZ2FtZTEgPC0gZ2V0U3B5QW5kR2FtZURhdGFGb3JPbmVHYW1lKHNweWRhdGEsIHNhbXBsZXdvcmxkY3VwZ2FtZXMsIDEsIDMpCnZvbHVtZXNwMSA8LSBnZ3Bsb3QoZ2FtZTEpICsgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHg9ZGF0ZSwgeT1sb2codm9sdW1lKSksIGNvbG9yID0icmVkIikgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9IHNhbXBsZXdvcmxkY3VwZ2FtZXMkRGF0ZXRpbWVbMV0pICsgZ2d0aXRsZSgiVm9sdW1lIG92ZXIgVGltZSwgU2FtcGxlIEdhbWUgMSIpCnZvbHVtZXNwMQpgYGAKCmBgYHtyfQpnYW1lMiA8LSBnZXRTcHlBbmRHYW1lRGF0YUZvck9uZUdhbWUoc3B5ZGF0YSwgc2FtcGxld29ybGRjdXBnYW1lcywgMiwgMykKdm9sdW1lc3AyIDwtIGdncGxvdChnYW1lMikgKyBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeD1kYXRlLCB5PWxvZyh2b2x1bWUpKSwgY29sb3IgPSJyZWQiKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gc2FtcGxld29ybGRjdXBnYW1lcyREYXRldGltZVsyXSkrIGdndGl0bGUoIlZvbHVtZSBvdmVyIFRpbWUsIFNhbXBsZSBHYW1lIDIiKQp2b2x1bWVzcDIKI0VSUk9SIEFHQUlOIFdFIERPTlQgSEFWRSBGVUxMIERBVEEgRk9SIFRISVMgR0FNRQpgYGAKCmBgYHtyfQpnYW1lMyA8LSBnZXRTcHlBbmRHYW1lRGF0YUZvck9uZUdhbWUoc3B5ZGF0YSwgc2FtcGxld29ybGRjdXBnYW1lcywgMywgMykKdm9sdW1lc3AzIDwtIGdncGxvdChnYW1lMykgKyBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeD1kYXRlLCB5PWxvZyh2b2x1bWUpKSwgY29sb3IgPSJyZWQiKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gc2FtcGxld29ybGRjdXBnYW1lcyREYXRldGltZVszXSkrIGdndGl0bGUoIlZvbHVtZSBvdmVyIFRpbWUsIFNhbXBsZSBHYW1lIDMiKQp2b2x1bWVzcDMKYGBgCgpgYGB7cn0KZ2FtZTQgPC0gZ2V0U3B5QW5kR2FtZURhdGFGb3JPbmVHYW1lKHNweWRhdGEsIHNhbXBsZXdvcmxkY3VwZ2FtZXMsIDQsIDMpCnZvbHVtZXNwNCA8LSBnZ3Bsb3QoZ2FtZTQpICsgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHg9ZGF0ZSwgeT1sb2codm9sdW1lKSksIGNvbG9yID0icmVkIikgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9IHNhbXBsZXdvcmxkY3VwZ2FtZXMkRGF0ZXRpbWVbNF0pKyBnZ3RpdGxlKCJWb2x1bWUgb3ZlciBUaW1lLCBTYW1wbGUgR2FtZSA0IikKdm9sdW1lc3A0CmBgYAoKYGBge3J9CmdhbWU1IDwtIGdldFNweUFuZEdhbWVEYXRhRm9yT25lR2FtZShzcHlkYXRhLCBzYW1wbGV3b3JsZGN1cGdhbWVzLCA1LCAzKQp2b2x1bWVzcDUgPC0gZ2dwbG90KGdhbWU1KSArIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4PWRhdGUsIHk9bG9nKHZvbHVtZSkpLCBjb2xvciA9InJlZCIpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PSBzYW1wbGV3b3JsZGN1cGdhbWVzJERhdGV0aW1lWzVdKSsgZ2d0aXRsZSgiVm9sdW1lIG92ZXIgVGltZSwgU2FtcGxlIEdhbWUgNSIpCnZvbHVtZXNwNQpgYGAKCiMjIFByaWNlIFNjYXR0ZXIgUGxvdHMKClVzaW5nIGF2ZXJhZ2UgcHJpY2UKCmBgYHtyfQpwcmljZXNwMSA8LSBnZ3Bsb3QoZ2FtZTEpICsgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHg9ZGF0ZSwgeT1hdmVyYWdlKSwgY29sb3IgPSJyZWQiKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gc2FtcGxld29ybGRjdXBnYW1lcyREYXRldGltZVsxXSkrIGdndGl0bGUoIlByaWNlIG92ZXIgVGltZSwgU2FtcGxlIEdhbWUgMSIpCnByaWNlc3AxCmBgYAoKYGBge3J9CnByaWNlc3AyIDwtIGdncGxvdChnYW1lMikgKyBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeD1kYXRlLCB5PWF2ZXJhZ2UpLCBjb2xvciA9InJlZCIpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PSBzYW1wbGV3b3JsZGN1cGdhbWVzJERhdGV0aW1lWzJdKSsgZ2d0aXRsZSgiUHJpY2Ugb3ZlciBUaW1lLCBTYW1wbGUgR2FtZSAyIikKcHJpY2VzcDIKI0lTU1VFIEJFQ0FVU0UgV0UgRE9OVCBIQVZFIERBVEEgRk9SIDE2OjAwIGFuZCB0aGF0IGlzIHRpbWUgb2YgdGhlIGdhbWUKYGBgCgpgYGB7cn0KcHJpY2VzcDMgPC0gZ2dwbG90KGdhbWUzKSArIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4PWRhdGUsIHk9YXZlcmFnZSksIGNvbG9yID0icmVkIikgKyBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQ9IHNhbXBsZXdvcmxkY3VwZ2FtZXMkRGF0ZXRpbWVbM10pKyBnZ3RpdGxlKCJQcmljZSBvdmVyIFRpbWUsIFNhbXBsZSBHYW1lIDMiKQpwcmljZXNwMwpgYGAKCmBgYHtyfQpwcmljZXNwNCA8LSBnZ3Bsb3QoZ2FtZTQpICsgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHg9ZGF0ZSwgeT1hdmVyYWdlKSwgY29sb3IgPSJyZWQiKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gc2FtcGxld29ybGRjdXBnYW1lcyREYXRldGltZVs0XSkrIGdndGl0bGUoIlByaWNlIG92ZXIgVGltZSwgU2FtcGxlIEdhbWUgNCIpCnByaWNlc3A0CmBgYAoKYGBge3J9CnByaWNlc3A1IDwtIGdncGxvdChnYW1lNSwgYWVzKGRhdGUpKSArIGdlb21fcG9pbnQoYWVzKHk9YXZlcmFnZSwgKSwgY29sb3IgPSJyZWQiKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gc2FtcGxld29ybGRjdXBnYW1lcyREYXRldGltZVs1XSkrIGdndGl0bGUoIlByaWNlIG92ZXIgVGltZSwgU2FtcGxlIEdhbWUgNSIpICsgZ2VvbV9jb2woYWVzKHk9KHZvbHVtZSkpKSArIHNjYWxlX3lfY29udGludW91cyhzZWMuYXhpcyA9IHNlY19heGlzKH4uLzEwMCwgbmFtZSA9ICJhdmVyYWdlIikpCnByaWNlc3A1CmBgYAoKIyMgSnVzdCBVU0EgR2FtZXMKCmBgYHtyfQp3b3JsZGN1cG1hdGNoZXNVU0Fob21lID0gZmlsdGVyKGNsZWFuZWRfd29ybGRjdXBtYXRjaGVzLCBIb21lLlRlYW0uTmFtZSA9PSAiVVNBIikKd29ybGRjdXBtYXRjaGVzVVNBYXdheSA9IGZpbHRlcihjbGVhbmVkX3dvcmxkY3VwbWF0Y2hlcywgQXdheS5UZWFtLk5hbWUgPT0gIlVTQSIpCndvcmxkY3VwbWF0Y2hlc1VTQSA8LSB1bmlvbl9hbGwod29ybGRjdXBtYXRjaGVzVVNBYXdheSx3b3JsZGN1cG1hdGNoZXNVU0Fob21lKQp3b3JsZGN1cG1hdGNoZXNVU0EKYGBgCgpgYGB7cn0KZ2FtZTFVU0EgPC0gZ2V0U3B5QW5kR2FtZURhdGFGb3JPbmVHYW1lKHNweWRhdGEsIHdvcmxkY3VwbWF0Y2hlc1VTQSwgMSwgMykKdm9sdW1lc3AxVVNBIDwtIGdncGxvdChnYW1lMVVTQSkgKyBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeD1kYXRlLCB5PWxvZyh2b2x1bWUpKSwgY29sb3IgPSJyZWQiKSArIGdlb21fdmxpbmUoeGludGVyY2VwdD0gd29ybGRjdXBtYXRjaGVzVVNBJERhdGV0aW1lWzFdKSsgZ2d0aXRsZSgiVm9sdW1lIG92ZXIgVGltZSwgVVNBIEdhbWUgMSwgMjAxMCIpCnZvbHVtZXNwMVVTQQpgYGAKCmBgYHtyfQpnYW1lMlVTQSA8LSBnZXRTcHlBbmRHYW1lRGF0YUZvck9uZUdhbWUoc3B5ZGF0YSwgd29ybGRjdXBtYXRjaGVzVVNBLCAyLCAzKQp2b2x1bWVzcDJVU0EgPC0gZ2dwbG90KGdhbWUyVVNBKSArIGdlb21fcG9pbnQobWFwcGluZyA9IGFlcyh4PWRhdGUsIHk9bG9nKHZvbHVtZSkpLCBjb2xvciA9InJlZCIpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PSB3b3JsZGN1cG1hdGNoZXNVU0EkRGF0ZXRpbWVbMl0pKyBnZ3RpdGxlKCJWb2x1bWUgb3ZlciBUaW1lLCBVU0EgR2FtZSAyLCAyMDE0IikKdm9sdW1lc3AyVVNBCmBgYAoKYGBge3J9CmdhbWUzVVNBIDwtIGdldFNweUFuZEdhbWVEYXRhRm9yT25lR2FtZShzcHlkYXRhLCB3b3JsZGN1cG1hdGNoZXNVU0EsIDMsIDMpCnZvbHVtZXNwM1VTQSA8LSBnZ3Bsb3QoZ2FtZTNVU0EpICsgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHg9ZGF0ZSwgeT12b2x1bWUpLCBjb2xvciA9InJlZCIpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PSB3b3JsZGN1cG1hdGNoZXNVU0EkRGF0ZXRpbWVbM10pKyBnZ3RpdGxlKCJWb2x1bWUgb3ZlciBUaW1lLCBVU0EgR2FtZSAyLCAyMDEwIikKdm9sdW1lc3AzVVNBCmBgYAoKYGBge3J9CmdhbWU0VVNBIDwtIGdldFNweUFuZEdhbWVEYXRhRm9yT25lR2FtZShzcHlkYXRhLCB3b3JsZGN1cG1hdGNoZXNVU0EsIDQsIDMpCnZvbHVtZXNwNFVTQSA8LSBnZ3Bsb3QoZ2FtZTRVU0EpICsgZ2VvbV9wb2ludChtYXBwaW5nID0gYWVzKHg9ZGF0ZSwgeT12b2x1bWUpLCBjb2xvciA9InJlZCIpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PSB3b3JsZGN1cG1hdGNoZXNVU0EkRGF0ZXRpbWVbNF0pKyBnZ3RpdGxlKCJWb2x1bWUgb3ZlciBUaW1lLCBVU0EgR2FtZSAxLCAyMDE0IikKdm9sdW1lc3A0VVNBCmBgYAoKYGBge3J9CnByaWNlc3A0VVNBIDwtIGdncGxvdChnYW1lNFVTQSkgKyBnZW9tX3BvaW50KG1hcHBpbmcgPSBhZXMoeD1kYXRlLCB5PWF2ZXJhZ2UpLCBjb2xvciA9InJlZCIpICsgZ2VvbV92bGluZSh4aW50ZXJjZXB0PSB3b3JsZGN1cG1hdGNoZXNVU0EkRGF0ZXRpbWVbNF0pKyBnZ3RpdGxlKCJQcmljZSBvdmVyIFRpbWUsIFVTQSBHYW1lIDEsIDIwMTQiKQpwcmljZXNwNFVTQQpgYGAKCiMgSXMgdGhlcmUgYSB3YXkgdG8gbWFrZSBtb25leSBkdXJpbmcgV29ybGQgQ3VwIEdhbWVzPwoKIyBXaGF0IHRpbWUgc2hvdWxkIHlvdSBsb29rIHRvIHNlbGw/CgpgYGB7cn0KcHJpY2VfbGlzdCA9IGMoKQp0aW1lX2xpc3QgPSBjKCkKZm9yIChnYW1lIGluIDE6bnJvdyhjbGVhbmVkX3dvcmxkY3VwbWF0Y2hlcykpIHsKICBwcmljZV9nYW1lX2RhdGEgPC0gZ2V0U3B5QW5kR2FtZURhdGFGb3JPbmVHYW1lKHNweWRhdGEsIGNsZWFuZWRfd29ybGRjdXBtYXRjaGVzLCBnYW1lLCAzKQogIGhpZ2hlc3RkYXRhcG9pbnQgPSBwcmljZV9nYW1lX2RhdGFbd2hpY2gubWF4KHByaWNlX2dhbWVfZGF0YSRhdmVyYWdlKSxdCiAgaGlnaGVzdHByaWNlZm9yZ2FtZSA8LSBoaWdoZXN0ZGF0YXBvaW50JGF2ZXJhZ2UKICB0aW1lIDwtIGhpZ2hlc3RkYXRhcG9pbnQkInRpbWUuZnJvbS5nYW1lIgogIHByaWNlX2xpc3QgPSBhcHBlbmQocHJpY2VfbGlzdCwgaGlnaGVzdHByaWNlZm9yZ2FtZSkKICB0aW1lX2xpc3QgPSBhcHBlbmQodGltZV9saXN0LCB0aW1lKQp9CmBgYAoKYGBge3J9Cm9wdGltYWxfc2VsbGluZy5kZiA8LSBkYXRhLmZyYW1lKCJwcmljZSIgPSBwcmljZV9saXN0LCAidGltZSIgPSB0aW1lX2xpc3QpCm9wdGltYWxfc2VsbGluZy5kZgpgYGAKCkRvIFRIaXMgZm9yIE9wdGltYWwgQnV5aW5nIHRpbWU/CgpgYGB7cn0KZ2dwbG90KG9wdGltYWxfc2VsbGluZy5kZikgKyBnZW9tX2hpc3RvZ3JhbShtYXBwaW5nID0gYWVzKHg9IHRpbWUpKSArIGdndGl0bGUoIkhvdyBPZnRlbiBCZXN0IFNlbGxpbmcgVGltZSBpcyB2cy4gVGltZSBGcm9tIEdhbWUiKQpgYGAKCiMgV2hhdCB0aW1lIHNob3VsZCB5b3UgbG9vayB0byBidXk/CgpgYGB7cn0KcHJpY2VfbGlzdCA9IGMoKQp0aW1lX2xpc3QgPSBjKCkKZm9yIChnYW1lIGluIDE6bnJvdyhjbGVhbmVkX3dvcmxkY3VwbWF0Y2hlcykpIHsKICBwcmljZV9nYW1lX2RhdGEgPC0gZ2V0U3B5QW5kR2FtZURhdGFGb3JPbmVHYW1lKHNweWRhdGEsIGNsZWFuZWRfd29ybGRjdXBtYXRjaGVzLCBnYW1lLCAzKQogIGxvd2VzdGRhdGFwb2ludCA9IHByaWNlX2dhbWVfZGF0YVt3aGljaC5taW4ocHJpY2VfZ2FtZV9kYXRhJGF2ZXJhZ2UpLF0KICBsb3dlc3RwcmljZWZvcmdhbWUgPC0gbG93ZXN0ZGF0YXBvaW50JGF2ZXJhZ2UKICB0aW1lIDwtIGxvd2VzdGRhdGFwb2ludCQidGltZS5mcm9tLmdhbWUiCiAgcHJpY2VfbGlzdCA9IGFwcGVuZChwcmljZV9saXN0LCBsb3dlc3RwcmljZWZvcmdhbWUpCiAgdGltZV9saXN0ID0gYXBwZW5kKHRpbWVfbGlzdCwgdGltZSkKfQpgYGAKCmBgYHtyfQpvcHRpbWFsX2J1eWluZy5kZiA8LSBkYXRhLmZyYW1lKCJwcmljZSIgPSBwcmljZV9saXN0LCAidGltZSIgPSB0aW1lX2xpc3QpCmdncGxvdChvcHRpbWFsX2J1eWluZy5kZikgKyBnZW9tX2hpc3RvZ3JhbShtYXBwaW5nID0gYWVzKHg9IHRpbWUpKSArIGdndGl0bGUoIkhvdyBPZnRlbiBCZXN0IEJ1eWluZyBUaW1lIGlzIHZzLiBUaW1lIEZyb20gR2FtZSIpCmBgYAoKIyBEb2VzIHRoZSBpbXBvcnRhbmNlIG9mIHRoZSBnYW1lIG1hdHRlciBpbiB0aGUgdG90YWwgYW1vdW50IG9mIHRyYWRlcz8KCmBgYHtyfQojVHJhbnNsYXRlIFJvdW5kIElECgpnZ3Bsb3QoYWxsc3B5ZGF0YSwgYWVzKHZvbHVtZSwgU3RhZ2UpKSArIGdlb21fYm94cGxvdCgpCmBgYAo=